using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ClientCommonWpf;
using Director.DomainModels;
using Director.Indicators;
using Director.Indicators.Basic;

namespace Director.ViewModels
{
	class ChartVM : AbstractDocVM
	{
		private readonly Security _security;
		private WriteableBitmap _bitmap;
		private Image _image;
		private Candle[] _candles;
		private int _position;
		private int _candleWidth;
		private readonly Charter _charter = new Charter();
		private bool _isReal;

		public ObservableCollection<ChartIndicator> Indicators { get; private set; }

		public DataManager DataManager { get { return DataManager.Instance; } }

		public bool IsReal
		{
			get { return _isReal; }
			set
			{
				_isReal = value;
				Draw();
			}
		}

		public ChartVM(MainVM mainVM, Security security, TimeFrame timeFrame):base(mainVM)
		{
			_security = security;
			ListenTimeFrame = timeFrame;
		}

		public override void Init()
		{
			Indicators = new ObservableCollection<ChartIndicator>(new ChartIndicator[]
			{
				new ChartSimpleMovingAverage(candle => candle.Close) {Length = 50, Color = Colors.Goldenrod, Name = "Slow"}, 
				//new ChartSimpleMovingAverage(candle => candle.Close) {Length = 100, Color = Colors.GreenYellow, Name = "Med"}, 
				//new ChartSimpleMovingAverage(candle => candle.Close) {Length = 150, Color = Colors.Goldenrod, Name="Fast"}, 
				new ChartFractals(11){Color = Colors.Blue}, 
			});
			_candles = new Candle[0];
			_candleWidth = 1;
			_bitmap = BitmapFactory.New(1000, 1000);

			BuyCommand = new RelayCommand(ExecuteBuyCommand);
			SellCommand = new RelayCommand(ExecuteSellCommand);
			
			StartListenCandles(_security);
			Candles = MainVM.GetCandles(_security, ListenTimeFrame).OrderBy(e => e.Date).ToArray();
			Draw();
		}

		public ChartVM(MainVM mainVM, string contentKey):base(mainVM)
		{
			MainVM = mainVM;
			var split = contentKey.Split(SEPEARATOR);
			_security = DataManager.Instance.Securities.Values.Single(e => e.Code == split[0] && e.Board == split[1]);
			ListenTimeFrame = DataManager.Instance.TimeFrames.Single(e => e.TimeFrameLength == int.Parse(split[2]));
		}

		public override string Title
		{
			get { return _security.Name + " @ " + ListenTimeFrame; }
		}

		public override string ContentId
		{
			get
			{
				return DocId + MainVM.DOC_CONTENTID_SEPARATOR + _security.Code + SEPEARATOR + _security.Board + SEPEARATOR + ListenTimeFrame.TimeFrameLength;
			}
		}

		public override EDocId DocId
		{
			get { return EDocId.CHART; }
		}

		public override void CandlesUpdated()
		{
			//if (securityIds.Contains(_security.Id))
			{
				Candles = MainVM.GetCandles(_security, ListenTimeFrame).OrderBy(e => e.Date).ToArray();
				Draw();
			}
		}

		public ImageSource ImageSource
		{
			get { return _bitmap; }
		}

		public int Maximum
		{
			get
			{
				var maximum = _candles.Length - ImageActualWidth / _candleWidth + 10;
				if (_position > maximum)
				{
					Position = maximum;
					OnPropertyChanged(() => Position);
				}
				return maximum;
			}
		}

		public Image Image
		{
			get { return _image; }
			set
			{
				_image = value;
				_image.SizeChanged += Resize;
				_image.MouseMove += MouseMove;
				_image.MouseWheel += OnMouseWheel;
			}
		}

		public int ImageActualWidth
		{
			get { return _image == null ? 0 : (int)_image.ActualWidth; }
		}

		private void MouseMove(object sender, MouseEventArgs e)
		{
			MousePosition = e.GetPosition(Image);
			Draw();
		}

		public Point MousePosition { get; set; }

		public int Position
		{
			get { return _position; }
			set
			{
				_position = value;
				Draw();
			}
		}

		public int CandleWidth
		{
			get { return _candleWidth; }
			set
			{
				_candleWidth = value;
				OnPropertyChanged(() => Maximum);
				Draw();
			}
		}

		private void Resize(object sender, SizeChangedEventArgs sizeChangedEventArgs)
		{
			OnPropertyChanged(() => ImageActualWidth);
			OnPropertyChanged(() => Maximum);
			Draw();
		}

		void OnMouseWheel(object sender, MouseWheelEventArgs e)
		{
			var v = CandleWidth + Math.Sign(e.Delta);
			if (v < 1) v = 1;
			else if (v > 20) v = 20;
			CandleWidth = v;
			OnPropertyChanged(() => CandleWidth);
		}

		private void Draw()
		{
			if (Image == null) return;

			if (Position < 0)
			{
				Position = 0;
				return;
			}

			var w = Image.ActualWidth;
			var h = Image.ActualHeight;
			_bitmap = _charter.Draw(_bitmap, w, h, MousePosition, CandleWidth, Position, ListenTimeFrame, _security, IsReal);
			OnPropertyChanged(() => ImageSource);
		}

		public Candle[] Candles
		{
			get { return _candles; }
			set
			{
				var end = Position >= _candles.Count();
				_candles = value;
				_charter.Candles = value;
				foreach (var indicator in Indicators)
				{
					indicator.Calc(_candles);
				}
				_charter.Indicators = Indicators.ToArray();
				OnPropertyChanged(()=>Maximum);
				if (end)
				{
					Position = Maximum;
					OnPropertyChanged(()=>Position);
				}
			}
		}

		public TimeFrame TimeFrame
		{
			get { return ListenTimeFrame; }
			set
			{
				if (ListenTimeFrame == value) return;
				ListenTimeFrame = value;
				OnPropertyChanged(() => ContentId);
				OnPropertyChanged(() => Title);
				MainVM.GetHistory(_security, ListenTimeFrame);
				StartListenCandles(_security);
				Candles = MainVM.GetCandles(_security, ListenTimeFrame).OrderBy(e => e.Date).ToArray();
			}
		}

		#region BuyCommand

		public RelayCommand BuyCommand { get; private set; }

		private void ExecuteBuyCommand(object obj)
		{
			MainVM.Buy(_security, 1, "CHART");
		}

		#endregion

		#region SellCommand

		public RelayCommand SellCommand { get; private set; }

		private void ExecuteSellCommand(object obj)
		{
			MainVM.Sell(_security, 1, "CHART");
		}

		#endregion

	}
}